#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <cstring>
using namespace std;

namespace Protocol {
    const string ProtSep = " ";
    const string LineBreakSep = "\n";

    // 添加报头信息
    string Encode(const string& message) {
        if (message.empty()) {
            return string();
        }
        string len = to_string(message.size());
        string package = len + LineBreakSep + message + LineBreakSep;
        return package;
    }

    // 解包
    bool Decode(string& package, string* message) {
        auto pos = package.find(LineBreakSep);
        if (pos == string::npos) {
            return false;
        }
        string lens = package.substr(0, pos);
        int messagelen = stoi(lens);
        int totallen = lens.size() + messagelen + 2 * LineBreakSep.size();
        if (package.size() < totallen) {
            return false;
        }
        // 截取一个完成的报文
        *message = package.substr(pos + LineBreakSep.size(), messagelen);
        // 去除一个完成的报文
        package.erase(0, totallen);
        return true;


    }


    class Request {
    public :
        Request() 
            :_x(0)
            ,_y(0)
            ,_op(0)
        {
        }
        Request(int x, int y, char op) 
            :_x(x)
            ,_y(y)
            ,_op(op)
        {

        }
        ~Request() {

        }

        int GetX() {
            return _x;
        }
        int GetY() {
            return _y;
        }
        char GetOp() {
            return _op;
        }
        void SetX(int x) {
            _x = x;
        }
        void SetY(int y) {
            _y = y;
        }
        void SetOp(char op) {
            _op = op;
        }
        void Inc() {
            _x++;
            _y++;
        }

        // 序列化
        bool Serialize(string* out) {
            *out = to_string(_x) + ProtSep + _op + ProtSep + to_string(_y);
            return true;
        }
        // 反序列化
        bool DeSerialize(const string& in) {
            auto left = in.find(ProtSep);
            auto right = in.rfind(ProtSep);
            if (left == string::npos || right == string::npos) {
                return false;
            }
            if (left == right) {
                return false;
            }
            _x = stoi(in.substr(0, left));
            _y = stoi(in.substr(right + ProtSep.size()));
            string opers = in.substr(left + ProtSep.size(), right - (left + ProtSep.size()));
            if (opers.size() != 1) {
                return false;
            }
            _op = opers[0];
            return true;
        }



    private :
        int _x;
        int _y;
        char _op;
    };

    class Response {
    public :
        Response() {

        }
        Response(int result, int code) 
            :_result(result)
            ,_code(code)
        {}


        // 序列化
        bool Serialize(string* out) {
            *out = to_string(_result) + ProtSep + to_string(_code);
            return true;
        }
        // 反序列化
        bool DeSerialize(const string& in) {
            auto pos = in.find(ProtSep);
            if (pos == string::npos) {
                return false;
            }
            _result = stoi(in.substr(0, pos));
            _code = stoi(in.substr(pos + ProtSep.size()));
            return true;
        }
        int GetResult() {
            return _result;
        }
        int GetCode() {
            return _code;
        }
        void SetResult(int result) {
            _result = result;
        }
        void SetCode(int code) {
            _code = code;
        }
        ~Response() {

        }
    private :
        int _result;
        int _code;
    };




    // 简单的工程模式设计模式
    class Factory {
        public :
        shared_ptr<Request> BuildRequest() {
            return shared_ptr<Request>(new Request());
        }
        shared_ptr<Response> BuildResponse() {
            return shared_ptr<Response>(new Response());
        }

        shared_ptr<Request> BuildRequest(int x, int y, char op) {
            return shared_ptr<Request>(new Request(x, y, op));
        }
        shared_ptr<Response> BuildResponse(int result, int code) {
            return shared_ptr<Response>(new Response(result, code));
        }
    };
};



